package cn.mw.cmdb.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.mw.cmdb.entity.*;
import cn.mw.cmdb.enums.OperatorTypeDescEnum;
import cn.mw.cmdb.enums.ViewTypeEnum;
import cn.mw.cmdb.exception.ModelExistException;
import cn.mw.cmdb.exception.NotFindModelException;
import cn.mw.cmdb.exception.PropertyRepeatException;
import cn.mw.cmdb.exception.WarnTitleException;
import cn.mw.cmdb.mongoMapper.ModelInfoMapper;
import cn.mw.cmdb.mongoMapper.ModelPropertyCatologMapper;
import cn.mw.cmdb.mongoMapper.ModelPropertySortMapper;
import cn.mw.cmdb.param.FunctionModuleEnum;
import cn.mw.cmdb.param.ModelPropertyParam;
import cn.mw.cmdb.param.ModelSearchParam;
import cn.mw.cmdb.param.PropertySearchParam;
import cn.mw.cmdb.util.CMDBTool;
import cn.mw.cmdb.view.*;
import cn.mw.components.mongodb.config.MongoConstant;
import cn.mw.components.mongodb.entity.CriteriaOpsType;
import cn.mw.components.mongodb.entity.SearchParam;
import cn.mw.components.mongodb.entity.SubCondition;
import cn.mw.components.mongodb.tool.CriteriaWrapper;
import cn.mw.log.client.LogClientSimple;
import cn.mw.log.enums.BusinessLogType;
import cn.mw.log.enums.LogLevel;
import cn.mw.microMonitorCommon.constant.Constants;
import cn.mw.microMonitorCommon.entity.cmdb.RelatedDataType;
import cn.mw.microMonitorCommon.security.utils.SecurityUtils;
import cn.mw.microMonitorCommon.util.DateUtils;
import com.alibaba.nacos.common.utils.CollectionUtils;
import com.google.common.base.Strings;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.data.mongodb.core.BulkOperations;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.util.Pair;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;

import static cn.mw.cmdb.controller.MwProcessCallCMDBController.propertyCatologTypeList;
import static cn.mw.cmdb.entity.FieldAuthType.getFieldAuthTypeByName;
import static cn.mw.cmdb.entity.InputDataAuth.*;
import static cn.mw.cmdb.entity.PropertyType.createrPath;
import static cn.mw.cmdb.entity.PropertyType.modifierPath;
import static cn.mw.cmdb.entity.PropertyTypeStruct.structPropertyTypeRef;
import static cn.mw.cmdb.enums.ModelConfigKeyEnum.commonParentModels;
import static cn.mw.cmdb.enums.PageDescEnum.ModelProperty;
import static cn.mw.cmdb.service.impl.InstanceViewImpl.idKey;
import static cn.mw.cmdb.util.CMDBCommonUtil.sortListByField;
import static cn.mw.cmdb.util.ListSortUtil.sortListByTypeOrder;
import static cn.mw.cmdb.util.ValConvertUtil.booleanValueConvert;
import static cn.mw.cmdb.util.ValConvertUtil.strValueConvert;
import static cn.mw.cmdb.view.ViewConvert.ascSortModel;

@Slf4j
public class ModelPropertyServiceImpl extends ModelBaseServiceImpl<ModelPropertyParam, Object> {
    public static final String ID = "modelPropertyService";
    public static final List<String> defaultViewAuthList = Arrays.asList(FieldViewAuthType.list.name(), FieldViewAuthType.sel.name());
    public static final String DEFAULT_PROPERTY_CARD = "默认属性";
    public static final String keyWord = "keyWord";
    public static final String customKey = "自定义";
    public static final String propertyCatologListKey = "propertyCatologList";
    public static final String fieldViewAuthListKey = "fieldViewAuthList";

    public static final String fieldViewAuthTypesKey = "fieldViewAuthTypes";

    private ModelInfoMapper custModelMapper;

    private CmdbServiceManage cmdbServiceManage;

    private ModelPropertyCatologMapper modelPropertyCatologMapper;
    private LogClientSimple logClientSimple;
    private ModelPropertySortMapper modelPropertySortMapper;

    private ViewManager viewManager;

    public ModelPropertyServiceImpl(ModelInfoMapper custModelMapper, CmdbServiceManage cmdbServiceManage
            , ModelPropertyCatologMapper modelPropertyCatologMapper, ModelPropertySortMapper modelPropertySortMapper
            , ViewManager viewManager) {
        this.custModelMapper = custModelMapper;
        this.cmdbServiceManage = cmdbServiceManage;
        this.modelPropertyCatologMapper = modelPropertyCatologMapper;
        this.modelPropertySortMapper = modelPropertySortMapper;
        this.viewManager = viewManager;
    }

    public ModelPropertyServiceImpl() {
        this.logClientSimple = SpringUtil.getBean(LogClientSimple.class);
    }

    private static int compare(String source1, String source2) {
// "自定义" should come first
        if (customKey.equals(source1) && !customKey.equals(source2)) {
            return -1;
        } else if (!customKey.equals(source1) && customKey.equals(source2)) {
            return 1;
        } else if (source1 == null && source2 != null) {
            return 1;
        } else if (source1 != null && source2 == null) {
            return -1;
        } else if (source1 == null && source2 == null) {
            return 0;
        } else {
            return source1.compareTo(source2);
        }
    }


    private static int compareByPropertyInfo(PropertyInfo info1, PropertyInfo info2) {
// "自定义" should come first
        String source1 = info1.getPropertySource();
        String source2 = info2.getPropertySource();
        return compare(source1, source2);
    }

    private static int compareByModelPropertyParam(ModelPropertyParam info1, ModelPropertyParam info2) {
// "自定义" should come first
        String source1 = info1.getPropertySource();
        String source2 = info2.getPropertySource();
        return compare(source1, source2);
    }

    @Override
    public ModelPropertyParam genObject() {
        return new ModelPropertyParam();
    }

    @Override
    Object doAdd(ModelPropertyParam param) throws Exception {
        Query query = new Query(CriteriaWrapper.where(ModelInfo::getId).is(param.getModelId()));
        if (!StringUtils.hasText(param.getId())) {
            String id = UUID.randomUUID().toString();
            param.setId(id);
        }
        //如果属性分类为空，则设为默认属性
        if (Strings.isNullOrEmpty(param.getPropertyCatologName())) {
            param.setPropertyCatologName(DEFAULT_PROPERTY_CARD);
        }
        //设置权限关联字段
        setAuthRelatedData(param);
        checkPropertyData(param, true);
        Map map = genEntityMap(param);
        Update update = new Update().set(getPropertyField(param.getId()), map);
        custModelMapper.updateFirst(query, update);
        return Boolean.valueOf(true);
    }

    @Override
    boolean doUpdate(ModelPropertyParam param) throws Exception {
//        addPropertyCatologAndModifyId(param);
        //如果属性分类为空，则设为默认属性
        if (Strings.isNullOrEmpty(param.getPropertyCatologName())) {
            param.setPropertyCatologName(DEFAULT_PROPERTY_CARD);
        }
        //是否自定义表示，true，自定义
        boolean isCustomFlag = param.getModelId() != null && param.getOwnModelId() != null && !param.getModelId().equals(param.getOwnModelId());
        //设置权限关联字段
        setAuthRelatedData(param);
        checkPropertyData(param, false);
        Map map = genEntityMap(param);
        List<MongoUpdSet> updSets = new ArrayList<>();
        genMongoUpdSetList(map, getPropertyField(param.getId()), updSets);
        if (updSets.size() > 0) {
            Update update = new Update();
            int count = 0;
            for (MongoUpdSet mongoUpdSet : updSets) {
                if (null != mongoUpdSet.getValue()) {
                    if (isCustomFlag) {
                        //自定义设置，过滤字段显示权限，属性分类、排序
                        if ((!mongoUpdSet.getKey().contains(propertyCatologListKey) && !mongoUpdSet.getKey().contains(fieldViewAuthListKey) && !mongoUpdSet.getKey().contains(fieldViewAuthTypesKey))) {
                            update.set(mongoUpdSet.getKey(), mongoUpdSet.getValue());
                            count++;
                        }
                    } else {
                        update.set(mongoUpdSet.getKey(), mongoUpdSet.getValue());
                        count++;
                    }

                }
            }
            if (count > 0) {
                Query query = new Query(CriteriaWrapper.where(ModelInfo::getId).is(param.getModelId()));
                custModelMapper.updateFirst(query, update);
            }
            //属性模型id和当前模型id不同，表示在普通模型下编辑父模型属性
            if (isCustomFlag) {
                customPropertySetting(param);
            }
        }
        return true;
    }

    @Override
    public boolean doRemove(ModelPropertyParam param) throws Exception {
        //modelId 和 ownModelId 不同，表示选中的属性为父模型
        Set<String> propertyIds = new HashSet<>();
        Update update = new Update();
        if (CollectionUtils.isNotEmpty(param.getDelParams())) {
            Set<String> ownModelds = param.getDelParams().stream().filter(s -> !Strings.isNullOrEmpty(s.getOwnModelId())).map(s -> s.getOwnModelId()).collect(Collectors.toSet());
            propertyIds = param.getDelParams().stream().filter(s -> !Strings.isNullOrEmpty(s.getPropertyId())).map(s -> s.getPropertyId()).collect(Collectors.toSet());
            ownModelds.remove(param.getModelId());
            if(ownModelds.size() > 0){
                throw new WarnTitleException("property_delete_error");
            }
        }
        Query query = new Query(CriteriaWrapper.where(ModelInfo::getId).is(param.getModelId()));
        if(CollectionUtils.isNotEmpty(param.getIds())){
            propertyIds.addAll(param.getIds());
        }
        for (String strId : propertyIds) {
            update.unset(getPropertyField(strId));
        }
        custModelMapper.updateFirst(query, update);
        return true;
    }

    @Override
    Object doBatchAdd(Object params) {
        return false;
    }

    @Override
    boolean doBatchUpdate(Object params) throws Exception {
        if (params != null && params instanceof List) {
            List<ModelPropertyParam> propertyParams = (List<ModelPropertyParam>) params;
//            List<PropertyInfo> propertyParams = new ArrayList<>();
            int count = 0;
            List<Pair<Query, Update>> updateList = new ArrayList<>();
            //UNORDERED是异步执行，有错误跳过继续执行；ORDERED时有序执行，遇到错误终止
            BulkOperations operations = custModelMapper.bulkOps(BulkOperations.BulkMode.UNORDERED, ModelTemplateInfo.class);
            for (ModelPropertyParam param : propertyParams) {
                //如果属性分类为空，则设为默认属性
                if (Strings.isNullOrEmpty(param.getPropertyCatologName())) {
                    param.setPropertyCatologName(DEFAULT_PROPERTY_CARD);
                }
                Map map = genEntityMap(param);
                List<MongoUpdSet> updSets = new ArrayList<>();
                genMongoUpdSetList(map, getPropertyField(param.getId()), updSets);
                if (updSets.size() > 0) {
                    Update update = new Update();
                    for (MongoUpdSet mongoUpdSet : updSets) {
                        if (null != mongoUpdSet.getValue()) {
                            update.set(mongoUpdSet.getKey(), mongoUpdSet.getValue());
                            count++;
                        }
                    }
                    if (count > 0) {
                        Query query = new Query(CriteriaWrapper.where(ModelInfo::getId).is(param.getModelId()));
                        Pair<Query, Update> updatePair = Pair.of(query, update);
                        updateList.add(updatePair);
                    }
                }

            }
            operations.updateMulti(updateList);
            operations.execute();
        }
        return true;
    }

    @Override
    ModelPropertyParam doSelectById(Object param) throws Exception {
        ModelPropertyParam modelPropertyParam = (ModelPropertyParam) param;
        ModelPropertyParam ret = new ModelPropertyParam();
        if (null != modelPropertyParam.getModelId()) {
            ModelInfo modelInfo = getModelInfo(modelPropertyParam.getModelId());
            if (null != modelInfo) {
                PropertyInfo propertyInfo = modelInfo.getPropertyInfo(modelPropertyParam.getId());
                // 添加兼容历史数据 默认设置视图及属性分类
                setDefaultViewTypeParam(propertyInfo);
                BeanUtil.copyProperties(propertyInfo, ret);
                ret.setModelId(modelPropertyParam.getModelId());
                ret.setPropertySource(Strings.isNullOrEmpty(propertyInfo.getPropertySource()) ? ModelScope.custom.getName() : propertyInfo.getPropertySource());
                ret.setModelId(propertyInfo.getModelId());
            }
        }
        return ret;
    }

    private void setDefaultViewTypeParam(PropertyInfo propertyInfo) {
        if (CollectionUtils.isEmpty(propertyInfo.getPropertyCatologList())) {
            propertyInfo.setPropertyCatologList(new ArrayList<>());
            PropertyCategoryVo propertyCategoryVo = new PropertyCategoryVo();
            propertyCategoryVo.setPropertyCatologName(propertyInfo.getPropertyCatologName());
            propertyCategoryVo.setViewType(ViewTypeEnum.instanceView.getName());
            propertyInfo.getPropertyCatologList().add(propertyCategoryVo);

            PropertyCategoryVo financeCategoryVo = new PropertyCategoryVo();
            financeCategoryVo.setViewType(ViewTypeEnum.financeView.getName());
            financeCategoryVo.setPropertyCatologName(propertyInfo.getPropertyCatologName());
            propertyInfo.getPropertyCatologList().add(financeCategoryVo);
        }
        if (CollectionUtils.isEmpty(propertyInfo.getFieldViewAuthList())) {
            propertyInfo.setFieldViewAuthList(new ArrayList<>());
            FieldViewAuthVo fieldViewAuthVo = new FieldViewAuthVo();
            fieldViewAuthVo.setFieldViewAuthTypes(propertyInfo.getFieldViewAuthTypes());
            fieldViewAuthVo.setViewType(ViewTypeEnum.instanceView.getName());
            propertyInfo.getFieldViewAuthList().add(fieldViewAuthVo);

            FieldViewAuthVo financeViewAuthVo = new FieldViewAuthVo();
            financeViewAuthVo.setFieldViewAuthTypes(propertyInfo.getFieldViewAuthTypes());
            financeViewAuthVo.setViewType(ViewTypeEnum.financeView.getName());
            propertyInfo.getFieldViewAuthList().add(financeViewAuthVo);
        }
    }

    @Override
   public List<ModelPropertyParam> doSelectList(Object param) throws Exception {
        PropertySearchParam propertySearchParam = (PropertySearchParam) param;
        List<ModelPropertyParam> modelPropertyParams = doSelectListWithFilter(propertySearchParam, null);
        FieldAuthType fieldAuthTypeByName = null;
        //自定义属性视图展示，属性分类显示设置
        getPropertyCustomInfo(modelPropertyParams, propertySearchParam.getModelId());

        //模型属性使用模糊查询时，
        String queryVal = propertySearchParam.getKeywordValue();
        if (CollectionUtils.isNotEmpty(modelPropertyParams) && SearchParam.keyword.equals(propertySearchParam.getOperation()) &&
                !Strings.isNullOrEmpty(queryVal)) {
            //属性字段权限转换
            if (getFieldAuthTypeByName(queryVal) != null) {
                fieldAuthTypeByName = getFieldAuthTypeByName(queryVal);
            }

            FieldAuthType finalFieldAuthTypeByName = fieldAuthTypeByName;
            //对属性id，name，来源，属性分类，默认值，字段权限进行模型查询过滤
            modelPropertyParams = modelPropertyParams.stream().filter(s -> (
                    s.getName().contains(queryVal)
                            || (s.getPropertySource() != null ? s.getPropertySource().contains(queryVal) : false)
                            || s.getId().contains(queryVal)
                            || (s.getPropertyCatologName() != null ? s.getPropertyCatologName().contains(queryVal) : false)
                            || (s.getPropertyTypeRef() != null ? (strValueConvert(s.getPropertyTypeRef().getDefaultValue()).contains(queryVal)) : false)
                            || ((s.getPropertyTypeRef() != null && s.getPropertyTypeRef().getPropertyType() != null) ? (s.getPropertyTypeRef().getPropertyType().getName() != null ? s.getPropertyTypeRef().getPropertyType().getName().contains(queryVal) : false) : false)
                            || ((s.getFieldAuthTypes() != null && finalFieldAuthTypeByName != null) ? s.getFieldAuthTypes().contains(finalFieldAuthTypeByName) : false)
            )).collect(Collectors.toList());
        }

        String modelId = propertySearchParam.getModelId();
        if (!sortPropertyByListInfo(modelPropertyParams, Arrays.asList(modelId))) {
            //默认排序
            propertyListSort(modelPropertyParams, ModelPropertyParam.class);
        }
        if (CollectionUtils.isNotEmpty(modelPropertyParams) && (!Strings.isNullOrEmpty(propertySearchParam.getSortName()) && !Strings.isNullOrEmpty(propertySearchParam.getSortOrder()))) {
            boolean isAsc = ascSortModel.equals(propertySearchParam.getSortOrder()) ? true : false;
            //列表字段排序
            sortListByField(modelPropertyParams, propertySearchParam.getSortName(), isAsc);
        }
        return modelPropertyParams;
    }


    public Map<String, String> getPropertyMapByModelId(String modelId) throws Exception {
        PropertySearchParam propertySearchParam = new PropertySearchParam();
        propertySearchParam.setModelId(modelId);
        List<ModelPropertyParam> modelPropertyParams = doSelectListWithFilter(propertySearchParam, null);
        Map<String, String> collect = modelPropertyParams.stream().collect(Collectors.toMap(s -> s.getId(), s -> s.getName(), (
                value1, value2) -> {
            return value2;
        }));
        return collect;
    }


    public boolean sortPropertyByListInfo(List data, List<String> modelIds) throws Exception {
        boolean isSortFlag = false;
        List<ModelInfo> modelInfos = new ArrayList<>();
        //模型id为多个时，才进行排序处理
//        if (CollectionUtils.isNotEmpty(modelIds) && modelIds.size() > 1) {
        CustomModelServiceImpl service = (CustomModelServiceImpl) cmdbServiceManage.getModelService(CustomModelServiceImpl.ID);
        List<String> fields = new ArrayList<>();
        fields.add(CMDBTool.getFieldName(ModelInfo::getSortNum));
        //获取模型排序信息
        modelInfos = service.getModelInfoByIncludesField(modelIds, fields);
        //对模型排序
        Collections.sort(modelInfos, (Comparator.comparing(ModelInfo::getSortNum, Comparator.nullsLast(Comparator.naturalOrder()))));
//        }
        Query query = new Query(CriteriaWrapper.where(ModelPropertySortInfo::getModelId).in(modelIds));
        //查询模型对应的属性排序信息
        List<ModelPropertySortInfo> propertySortInfos = modelPropertySortMapper.find(query);
        Map<String, List<String>> collect = propertySortInfos.stream().filter(s -> CollectionUtils.isNotEmpty(s.getPropertyIds())).collect(Collectors.toMap(s -> s.getModelId(), s -> s.getPropertyIds()));
        if (CollectionUtils.isNotEmpty(propertySortInfos)) {
            List<String> propertyAllId = new ArrayList<>();
            for (ModelInfo modelInfo : modelInfos) {
                //按照模型排序，分先后顺序加入属性
                if (collect != null && collect.containsKey(modelInfo.getId())) {
                    propertyAllId.addAll(collect.get(modelInfo.getId()));
                }
            }
            if (CollectionUtils.isNotEmpty(propertyAllId)) {
                //为true，表示有排序属性数据，已排序
                isSortFlag = true;
            }
            sortListByTypeOrder(data, CMDBTool.getFieldName(ModelPropertyParam::getId), propertyAllId);
        }
        return isSortFlag;
    }


    public List<ModelPropertyParam> doSelectListWithFilter(Object param, Function<ModelPropertyParam, Boolean> filter) throws Exception {
        PropertySearchParam propertySearchParam = (PropertySearchParam) param;
        List<ModelPropertyParam> ret = new ArrayList<>();
        if (null != propertySearchParam.getModelId()) {
            ModelInfo modelInfo = getModelInfo(propertySearchParam.getModelId());
            if (null != modelInfo) {
                List<PropertyInfo> values = modelInfo.getPropertyInfoList();
                CustomModelServiceImpl modelService = (CustomModelServiceImpl) cmdbServiceManage.getModelService(CustomModelServiceImpl.ID);
                Set<String> modelIdSet = values.stream().map(s -> s.getModelId()).collect(Collectors.toSet());
                List<ModelInfo> modelInfos = modelService.findByIds(new ArrayList<>(modelIdSet));
                Map<String, String> modelNameById = modelInfos.stream().collect(Collectors.toMap(s -> s.getId(), s -> s.getModelName()));

                //自定义属性视图展示，属性分类显示设置
                getPropertyCustomInfo(values, propertySearchParam.getModelId());
                List<PropertyInfo> list = values.stream().sorted(Comparator.comparing(PropertyInfo::getSortNum, Comparator.nullsLast(Comparator.naturalOrder()))).collect(Collectors.toList());
                for (PropertyInfo propertyInfo : list) {
                    // 添加兼容历史数据 默认设置视图及属性分类
                    setDefaultViewTypeParam(propertyInfo);
                    ModelPropertyParam propertyParam = new ModelPropertyParam();
                    BeanUtil.copyProperties(propertyInfo, propertyParam);
                    propertyParam.setModelId(propertyInfo.getModelId());
                    propertyParam.setPropertySource(Strings.isNullOrEmpty(propertyInfo.getPropertySource()) ? ModelScope.custom.getName() : propertyInfo.getPropertySource());
                    propertyParam.setDistinctId(propertyInfo.getModelId() + "_" + propertyInfo.getId());
                    propertyParam.setOwnModelName(modelNameById.get(propertyInfo.getModelId()));
                    if (null != filter) {
                        if (filter.apply(propertyParam)) {
                            ret.add(propertyParam);
                        }
                    } else {
                        ret.add(propertyParam);
                    }
                }
            }
        }
        propertyListSort(ret, ModelPropertyParam.class);
        return ret;
    }

    List<ModelPropertyParam> doSelectFilterPrefixList(Object param) throws Exception {
        PropertySearchParam propertySearchParam = (PropertySearchParam) param;
        List<ModelPropertyParam> ret = new ArrayList<>();
        if (null != propertySearchParam.getModelId()) {
            ModelInfo modelInfo = getModelInfo(propertySearchParam.getModelId());
            if (null != modelInfo) {
                for (PropertyInfo propertyInfo : modelInfo.getPropertyInfoListFilterPrefix()) {
                    ModelPropertyParam propertyParam = new ModelPropertyParam();
                    BeanUtil.copyProperties(propertyInfo, propertyParam);
                    ret.add(propertyParam);
                }
            }
        }

        return ret;
    }


    public List<ModelPropertyParam> distinctListProperty(PropertySearchParam param) throws Exception {
        List<ModelPropertyParam> modelPropertyParams = doSelectListWithFilter(param, null);
        Map<String, List<ModelPropertyParam>> collect = modelPropertyParams.stream().collect(Collectors.groupingBy(s -> s.getId()));
        List<ModelPropertyParam> disList = new ArrayList<>();
        collect.forEach((k, v) -> {
            String propertyId = k;
            List<ModelPropertyParam> propertyInfos = v;
            String modelNames = "";
            if (CollectionUtils.isNotEmpty(propertyInfos)) {
                for (ModelPropertyParam propertyParam : propertyInfos) {
                    modelNames += propertyParam.getOwnModelName() + "/";
                }
                if (modelNames.length() > 1) {
                    modelNames = modelNames.substring(0, modelNames.length() - 1);
                }
                ModelPropertyParam propertyParam = propertyInfos.get(0);
                propertyParam.setMergedModelName(modelNames);
                disList.add(propertyParam);
            }
        });
        return disList;
    }


    @Override
    boolean doBatchRemove(Object params) throws Exception {
        return false;
    }

    public List<ModelPropertyParam> listInputProperty(PropertySearchParam param) throws Exception {
        // 查询模型所有父模型
        CustomModelServiceImpl modelService = (CustomModelServiceImpl) cmdbServiceManage.getModelService(CustomModelServiceImpl.ID);
        ModelSearchParam modelSearchParam = new ModelSearchParam();
        modelSearchParam.addSubCondition(CMDBTool.getFieldName(ModelInfo::getFunctionModule), new SubCondition(CriteriaOpsType.in.name(), FunctionModuleEnum.financeReport.getCode()));
        List<ModelInfo> financeParentModelInfos = modelService.getAllModelByParentGroup(modelSearchParam);
        Map<String, ModelInfo> modelId2FinanceParentModelInfoMap = financeParentModelInfos.stream().collect(Collectors.toMap(ModelInfo::getId, item -> item, (o1, o2) -> o1));
        List<String> financeParentModelIds = financeParentModelInfos.stream().map(ModelInfo::getId).toList();
        List<String> parentModelPropertiesId;
        if (StringUtils.hasText(param.getParentModelId()) && modelId2FinanceParentModelInfoMap.containsKey(param.getParentModelId())) {
            // 查询父模型属性
            ModelInfo parentModel = modelId2FinanceParentModelInfoMap.get(param.getParentModelId());
            parentModelPropertiesId = parentModel.getPropertyInfoList().stream().map(PropertyInfo::getId).toList();
        } else {
            parentModelPropertiesId = null;
        }

        List<ModelPropertyParam> ret = doSelectListWithFilter(param, (property) -> {
            String viewType = StringUtils.hasText(param.getViewType()) ? param.getViewType() : ViewTypeEnum.instanceView.getName();
            boolean result = false;
            // 指定了父模型 查询字段展示普通模型+父模型 否则只展示非金融元父模型字段 多个金融元父模型可能存在相同字段的情况 因此使用字段id匹配
            if (CollectionUtils.isNotEmpty(parentModelPropertiesId)) {
                if (financeParentModelIds.contains(property.getModelId()) && (!param.getParentModelId().equals(property.getModelId()) || !parentModelPropertiesId.contains(property.getId()))) {
                    return false;
                }
            } else if (financeParentModelIds.contains(property.getModelId())) {
                return false;
            }

            FieldViewAuthType fieldViewAuthType = FieldViewAuthType.valueOf(param.getInputType());
            // 按照视图过滤字段权限 资产视图兼容之前的老数据
            Set<FieldViewAuthType> fieldViewAuthTypes = ViewTypeEnum.instanceView.getName().equals(viewType) ? property.getFieldViewAuthTypes() : null;

            property.setFileViewAuth(viewType, param.getParentModelId());
            fieldViewAuthTypes = property.getFieldViewAuthTypes();

            if (CollectionUtils.isNotEmpty(property.getPropertyCatologList())) {
                for (PropertyCategoryVo propertyCategoryVo : property.getPropertyCatologList()) {
                    if (viewType.equals(propertyCategoryVo.getViewType())) {
                        property.setPropertyCatologName(propertyCategoryVo.getPropertyCatologName());
                        break;
                    }
                }
            }

            if (CollectionUtils.isNotEmpty(fieldViewAuthTypes) && fieldViewAuthTypes.contains(fieldViewAuthType)) {
                result = true;
            }
            return result;
        });
        propertyListSort(ret, ModelPropertyParam.class);
        return ret;
    }

    public List<PropertyInfo> listCommonProperty(List<TreeViewObject> treeViewObjectList) throws Exception {
        CustomModelServiceImpl modelService = (CustomModelServiceImpl) cmdbServiceManage.getModelService(CustomModelServiceImpl.ID);
        List<ModelInfo> modelInfoList = modelService.selectByTreeViewList(treeViewObjectList);
        List<PropertyInfo> ret = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(modelInfoList)) {
            List<PropertyInfo> propertyInfoList = new ArrayList<>();
            for (ModelInfo modelInfo : modelInfoList) {
                propertyInfoList.addAll(modelInfo.getPropertyInfoList());
            }
            Map<String, List<PropertyInfo>> key2PropertyInfoMap = propertyInfoList.stream().collect(Collectors.groupingBy(item -> item.getId() + "-" + item.getName()));
            for (Map.Entry<String, List<PropertyInfo>> entry : key2PropertyInfoMap.entrySet()) {
                if (entry.getValue().size() == modelInfoList.size()) {
                    ret.add(entry.getValue().get(0));
                }
            }
        }
        propertyListSort(ret, PropertyInfo.class);
        return ret;
    }


    /**
     * 设置属性视图
     *
     * @return
     * @throws Exception
     */
    public boolean settingPropertyShow(ModelPropertyParam batchParam) throws Exception {
        Query query = new Query(CriteriaWrapper.where(ModelInfo::getId).in(batchParam.getModelId()));
        Update update = new Update();
        List<String> viewList = new ArrayList<>();
        if (booleanValueConvert(batchParam.getEnableShow())) {
            //属性视图打开时，默认选择list，sel权限
            viewList = defaultViewAuthList;
        }
        if (CollectionUtils.isNotEmpty(batchParam.getIds())) {
            for (String id : batchParam.getIds()) {
                update.set(ModelInfo.PropertyMap + MongoConstant.FieldSep + id + MongoConstant.FieldSep + CMDBTool.getFieldName(PropertyInfo::getEnableShow), batchParam.getEnableShow());
                update.set(ModelInfo.PropertyMap + MongoConstant.FieldSep + id + MongoConstant.FieldSep + CMDBTool.getFieldName(PropertyInfo::getFieldViewAuthTypes), viewList);
            }
        }
        //视图关闭时，字段显示权限置空
        custModelMapper.updateFirst(query, update);
        return true;
    }


    /**
     * 根据父模型获取公共模型属性字段
     *
     * @return
     * @throws Exception
     */
    public List<PropertyInfo> getCommonModelPropertyInfos() throws Exception {
        long time1 = System.currentTimeMillis();
        MwCMDBConfigImpl configServer = (MwCMDBConfigImpl) cmdbServiceManage.getModelService(MwCMDBConfigImpl.ID);
        MwCMDBConfigInfo cmdbConfigInfo = configServer.doSelectByKey(commonParentModels.name());
        long time2 = System.currentTimeMillis();
        Object configValue = cmdbConfigInfo.getConfigValue();
        List<String> modelIds = new ArrayList<>();
        if (configValue instanceof List) {
            modelIds = (List<String>) configValue;
        }
        CustomModelServiceImpl modelServer = (CustomModelServiceImpl) cmdbServiceManage.getModelService(CustomModelServiceImpl.ID);
        List<ModelInfo> ret = modelServer.findByIds(modelIds);
        long time3 = System.currentTimeMillis();
        List<PropertyInfo> propertyInfoList = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(ret)) {
            for (ModelInfo modelInfo : ret) {
                if (CollectionUtils.isNotEmpty(modelInfo.getCurrentModelPropertyInfo())) {
                    propertyInfoList.addAll(modelInfo.getCurrentModelPropertyInfo());
                }
            }
        }
        long time4 = System.currentTimeMillis();
        log.info("getCommonModelPropertyInfos::getConfigValue:耗时：" + (time2 - time1) + "ms;doModelList耗时:" + (time3 - time2) + "ms;组装属性耗时:" + (time4 - time3) + "ms");
        propertyListSort(propertyInfoList, PropertyInfo.class);
        return propertyInfoList;
    }

    public static <T> void propertyListSort(List t, T clazz) {
        if (clazz.equals(PropertyInfo.class)) {
            Collections.sort(t, (Comparator.comparing(PropertyInfo::getSortNum, Comparator.nullsLast(Comparator.naturalOrder())).thenComparing(ModelPropertyServiceImpl::compareByPropertyInfo).thenComparing(PropertyInfo::getPropertyCatologName, Comparator.nullsLast(Comparator.naturalOrder())).thenComparing(PropertyInfo::getName, Comparator.nullsLast(Comparator.naturalOrder()))));
        }
        if (clazz.equals(ModelPropertyParam.class)) {
            Collections.sort(t, (Comparator.comparing(ModelPropertyParam::getSortNum, Comparator.nullsLast(Comparator.naturalOrder())).thenComparing(ModelPropertyServiceImpl::compareByModelPropertyParam).thenComparing(ModelPropertyParam::getPropertyCatologName, Comparator.nullsLast(Comparator.naturalOrder())).thenComparing(ModelPropertyParam::getName, Comparator.nullsLast(Comparator.naturalOrder()))));
        }
    }

    private String getPropertyField(String id) {
        return ModelInfo.PropertyMap + MongoConstant.FieldSep + id;
    }

    private String getPropertyCustomField(String id) {
        return ModelPropertySortInfo.CustomMap + MongoConstant.FieldSep + id;
    }

    //实体对象转map(多层级递归处理，需指定需要转换处理的实体类型)
    public static Map genEntityMap(Object param) {
        Map map = BeanUtil.beanToMap(param, false, true);
        Object value = map.remove(CMDBTool.CMDBDefaultIdKey);
        if (value != null) {
            map.put(MongoConstant.DefaultIdKey, value);
        }
        Set sets = new HashSet();
        sets.add(PropertyTypeRef.class);
        CMDBTool.cleanMongoDBClassKey(map, sets);
        return map;
    }

    private void genConvertToMap(Map map, Map ms) {
        Iterator<Map.Entry> iterator = map.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry entry = iterator.next();
            String key = (String) entry.getKey();
            Object value = entry.getValue();
            if (value instanceof Map) {
                genConvertToMap((Map) value, ms);
            } else {
                ms.put(key, value);
            }
        }
    }

    public static void genMongoUpdSetList(Map map, String prefix, List<MongoUpdSet> list) {
        Iterator<Map.Entry> iterator = map.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry entry = iterator.next();
            String key = prefix + MongoConstant.FieldSep + entry.getKey().toString();
            Object value = entry.getValue();
            if (value instanceof Map && !structPropertyTypeRef.equals(entry.getKey().toString())) {
                genMongoUpdSetList((Map) value, key, list);
            } else {
                MongoUpdSet mongoUpdSet = new MongoUpdSet(key, value);
                list.add(mongoUpdSet);
            }
        }
    }

    private ModelInfo getModelInfo(Object modelId) {
        CustomModelServiceImpl modelService = (CustomModelServiceImpl) cmdbServiceManage.getModelService(CustomModelServiceImpl.ID);
        ModelInfo modelInfo = modelService.doSelectById(modelId);
        return modelInfo;
    }

    private List<ModelInfo> getModelInfoByIds(List<String> modelIds) throws Exception {
        CustomModelServiceImpl modelService = (CustomModelServiceImpl) cmdbServiceManage.getModelService(CustomModelServiceImpl.ID);
        List<ModelInfo> modelInfos = modelService.findByIds(modelIds);
        return modelInfos;
    }

    /*
     * 检查属性分类的id,通过页面新增时,此时的id字段传入的是名称
     * 如果不存在该名称,则新增属性分类,并把值替换成生成的id
     */
//    public void addPropertyCatologAndModifyId(ModelPropertyParam param) throws Exception {
//        List<Criteria> criterias = new ArrayList<>();
//        //如果属性分类为空，则设为默认属性
//        if (Strings.isNullOrEmpty(param.getPropertyCatologName())) {
//            param.setPropertyCatologName(DEFAULT_PROPERTY_CARD);
//        }
//        criterias.add(CriteriaWrapper.where(ModelPropertyCatolog::getName).is(param.getPropertyCatologName()));
//        criterias.add(CriteriaWrapper.where(ModelPropertyCatolog::getModelId).is(param.getModelId()));
//        Query query = new Query().addCriteria(new Criteria().andOperator(criterias));
//        List<ModelPropertyCatolog> modelPropertyCatologs = modelPropertyCatologMapper.find(query);
//        if (null == modelPropertyCatologs || modelPropertyCatologs.size() == 0) {
//            ModelPropertyCatolog catolog = ModelPropertyCatolog.build(param.getModelId(), param.getPropertyCatologId());
//            ModelPropertyCatolog ret = modelPropertyCatologMapper.insert(catolog);
//            param.setPropertyCatologId(ret.getId());
//        } else {
//            param.setPropertyCatologId(modelPropertyCatologs.get(0).getId());
//        }
//    }

    //删除属性分类
    public void delModelPropertyCatolog(ModelPropertyCatolog catolog) throws Exception {
        Query query = null;

        if (StringUtils.hasText(catolog.getId())) {
            //根据分类id删除时,需要检查对应模型的属性是否引用了分类
            query = new Query().addCriteria(CriteriaWrapper.where(ModelPropertyCatolog::getId).is(catolog.getId()));
            ModelPropertyCatolog dbCatolog = modelPropertyCatologMapper.findById(catolog.getId());
            if (null != dbCatolog) {
                ModelInfo modelInfo = custModelMapper.findById(dbCatolog.getModelId());
                long count = 0;
                if (null != modelInfo && null != modelInfo.getProperties()) {
                    for (PropertyInfo propertyInfo : modelInfo.getProperties().values()) {
                        if (StringUtils.hasText(propertyInfo.getPropertyCatologName())
                                && catolog.getId().equals(propertyInfo.getPropertyCatologName())) {
                            count++;
                            break;
                        }
                    }
                }

                if (count > 0) {
                    throw new ModelExistException("model-exist-err");
                }
            }
        } else if (StringUtils.hasText(catolog.getModelId())) {
            //由于分类和模型是一一对应关系,当删除模型的时候,才会根据模型id删除
            //此时不需要检查
            query = new Query().addCriteria(CriteriaWrapper.where(ModelPropertyCatolog::getModelId).is(catolog.getModelId()));
        }

        if (null != query) {
            modelPropertyCatologMapper.remove(query);
        }
    }

    //显示属性分类列表
    public List<String> listModelPropertyCatolog(ModelPropertyCatolog param) throws Exception {
        ModelInfo modelInfo = getModelInfo(param.getModelId());
        Set<String> ret = new HashSet<>();
        if (null != modelInfo) {
            for (PropertyInfo propertyInfo : modelInfo.getPropertyInfoList()) {
                propertyInfo.getPropertyCatologName();
                if (!Strings.isNullOrEmpty(propertyInfo.getPropertyCatologName())) {
                    if (!propertyCatologTypeList.contains(propertyInfo.getPropertyCatologName())) {
                        ret.add(propertyInfo.getPropertyCatologName());
                    }
                }
            }
        }
        //属性字段中的分类列表
        List<String> list = new ArrayList<>(ret);
        //排序后的属性分类列表
        List<String> modelPropertyCatologList = modelInfo.getModelPropertyCatologList();
        if (modelPropertyCatologList != null) {
            list.removeAll(modelPropertyCatologList);
            modelPropertyCatologList.addAll(list);
        } else {
            modelPropertyCatologList = new ArrayList<>();
            modelPropertyCatologList = list;
        }
        return modelPropertyCatologList;
    }

    /**
     * 给定指定字段排序
     *
     * @param list
     * @param defaultValue
     */
    public static void sortListWithDefaultFirst(List<String> list, String defaultValue) {
        Collections.sort(list, new Comparator<String>() {
            @Override
            public int compare(String s1, String s2) {
                if (s1.equals(defaultValue) && s2.equals(defaultValue)) {
                    return 0;
                } else if (s1.equals(defaultValue)) {
                    return -1;
                } else if (s2.equals(defaultValue)) {
                    return 1;
                } else {
                    return s1.compareTo(s2);
                }
            }
        });
    }


    public List<ModelPropertyCatolog> listModelPropertyCatologByIds(List list) throws Exception {
        Query query = new Query(CriteriaWrapper.where(ModelPropertyCatolog::getId).in(list));
        return modelPropertyCatologMapper.find(query);
    }

    /**
     * 获取模型所有属性集合(包括继承的父模型属性)
     *
     * @param ids
     * @return
     * @throws Exception
     */
    public Map<String, List<PropertyInfo>> getModelAllPropertyList(List<String> ids, String financeParentId) throws
            Exception {
        CustomModelServiceImpl modelService = (CustomModelServiceImpl) cmdbServiceManage.getModelService(CustomModelServiceImpl.ID);
        List<ModelInfo> modelInfos = modelService.findByIds(ids);
        if (CollectionUtils.isEmpty(modelInfos)) {
            throw new NotFindModelException(strValueConvert(ids));
        }
        Set<String> modelIds = new HashSet<>();
        for (ModelInfo modelInfo : modelInfos) {
            if (CollectionUtils.isNotEmpty(modelInfo.getParentModelIds())) {
                modelIds.addAll(modelInfo.getParentModelIds());
            }
        }
        List<ModelInfo> parentModelInfos = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(modelIds)) {
            parentModelInfos = modelService.findByIds(new ArrayList<>(modelIds));
        }
        Map<String, ModelInfo> parentMapById = parentModelInfos.stream().collect(Collectors.toMap(s -> s.getId(), s -> s));
        Map<String, List<PropertyInfo>> map = new HashMap<>();
        boolean isAllParent = true;
        Set<String> allParentModelIds = new HashSet<>();
        for (ModelInfo modelInfo : modelInfos) {
            //判断普通模型
            if (!ModelType.Parent.equals(modelInfo.getModelType()) && parentMapById != null) {
                //获取父模型id
                List<String> parentModelIds = modelInfo.getParentModelIds();
                if (CollectionUtils.isNotEmpty(parentModelIds)) {
                    allParentModelIds.addAll(parentModelIds);
                }
                List<PropertyInfo> propertyInfoList = new ArrayList<>();
                isAllParent = false;
                //将本体的属性加入
                propertyInfoList.addAll(modelInfo.getCurrentModelPropertyInfo());
                if (CollectionUtils.isNotEmpty(parentModelIds)) {
                    for (String pId : parentModelIds) {
                        if (parentMapById != null && parentMapById.containsKey(pId)) {
                            //获取父模型信息
                            ModelInfo parentModelInfo = parentMapById.get(pId);
                            // 指定了金融元父模型的情况下,过滤其它金融元父模型的属性
                            if (StringUtils.hasText(financeParentId) && parentModelInfo.getFunctionModule() != null
                                    && parentModelInfo.getFunctionModule().contains(FunctionModuleEnum.financeReport.getCode())) {
                                if (financeParentId.equals(parentModelInfo.getId())) {
                                    //将父模型属性加入
                                    propertyInfoList.addAll(parentModelInfo.getCurrentModelPropertyInfo());
                                }
                            } else {
                                //将父模型属性加入
                                propertyInfoList.addAll(parentModelInfo.getCurrentModelPropertyInfo());
                            }
                            //父模型的属性，单独加入，父模型id为key，属性list为value
                            map.put(parentModelInfo.getId(), parentModelInfo.getCurrentModelPropertyInfo());
                        }
                    }
                }

                //组装成普通模型id为key，所有属性集合为value(包括继承的父模型属性)
                map.put(modelInfo.getId(), propertyInfoList);
            }
        }
        if (isAllParent) {
            List<ModelInfo> collect = modelInfos.stream().filter(s -> !allParentModelIds.contains(s.getId())).collect(Collectors.toList());
            for (ModelInfo modelInfo : collect) {
                map.put(modelInfo.getId(), modelInfo.getCurrentModelPropertyInfo());
            }
        }
        return map;
    }

    public Map<String, Map<String, PropertyInfo>> getPropertyInfosByModelId(List<String> modelIdLists) throws
            Exception {
        Map<String, List<PropertyInfo>> allPropertyList = getModelAllPropertyList(modelIdLists, null);

        // 转换后的Map,modelId为key，value中propertyId为key
        Map<String, Map<String, PropertyInfo>> resultMap = new HashMap<>();
        // 遍历原始Map进行转换
        for (Map.Entry<String, List<PropertyInfo>> entry : allPropertyList.entrySet()) {
            String key = entry.getKey();
            List<PropertyInfo> propertyList = entry.getValue();
            // 创建新的内部Map
            Map<String, PropertyInfo> innerMap = new HashMap<>();
            for (PropertyInfo property : propertyList) {
                innerMap.put(property.getId(), property);
            }
            // 将内部Map放入结果Map
            resultMap.put(key, innerMap);
        }
        return resultMap;
    }


    /**
     * 获取所有模型列表显示的属性
     *
     * @return
     * @throws Exception
     */
    public List<PropertyInfo> getAllModelByListShowProperty() throws Exception {
        List<PropertyInfo> propertyInfoList = new ArrayList<>();
        Consumer<ModelInfoContext> consumer = (context) -> {
            ModelInfo modelInfo = context.getModelInfo();
            context.getPropertyList().addAll(modelInfo.getListShowPropertyInfos());
        };
        propertyInfoList = doGetModelPropertyInfo(consumer);
        propertyListSort(propertyInfoList, PropertyInfo.class);
        return propertyInfoList;
    }

    /**
     * 获取所有模型的属性
     *
     * @return
     * @throws Exception
     */
    public List<PropertyInfo> getAllModelPropertyList() throws Exception {
        List<PropertyInfo> propertyInfoList = new ArrayList<>();
        Consumer<ModelInfoContext> consumer = (context) -> {
            ModelInfo modelInfo = context.getModelInfo();
            try {
                context.getPropertyList().addAll(modelInfo.getCurrentModelPropertyInfo());
            } catch (Exception e) {
                log.error("modelInfo.getCurrentModelPropertyInfo() to fail", e);
            }
        };
        propertyInfoList = doGetModelPropertyInfo(consumer);
        propertyListSort(propertyInfoList, PropertyInfo.class);
        return propertyInfoList;
    }


    private List<PropertyInfo> doGetModelPropertyInfo(Consumer<ModelInfoContext> consumer) throws Exception {
        CustomModelServiceImpl modelService = (CustomModelServiceImpl) cmdbServiceManage.getModelService(CustomModelServiceImpl.ID);
        ModelSearchParam searchParam = new ModelSearchParam();
        long time1 = System.currentTimeMillis();
        List<ModelInfo> modelInfos = modelService.findModelListByExistsProperty();
        long time2 = System.currentTimeMillis();

        List<PropertyInfo> propertyInfoList = new ArrayList<>();

        if (CollectionUtils.isNotEmpty(modelInfos)) {
            for (ModelInfo modelInfo : modelInfos) {
                ModelInfoContext modelInfoContext = new ModelInfoContext(modelInfo, propertyInfoList);
                consumer.accept(modelInfoContext);
            }
        }
        long time3 = System.currentTimeMillis();
        log.info("获取所有模型findAllList()耗时:" + (time2 - time1) + "ms;所有属性组装:" + (time3 - time2) + "ms");
        propertyListSort(propertyInfoList, PropertyInfo.class);
        return propertyInfoList;
    }

    /**
     * 获取所有外部关联属性Map
     *
     * @return
     * @throws Exception
     */
    public Map<String, PropertyInfo> getAllRelationPropertyMap() throws Exception {
        List<PropertyInfo> allModelPropertyList = getAllModelPropertyList();
        //外部关联属性
        Set<String> relationSet = new HashSet<>();
        relationSet.add(PropertyTypeExtSingle.ID);
        relationSet.add(PropertyTypeExtMultiple.ID);
        //获取所有外部关联的属性
        Map<String, PropertyInfo> collect = allModelPropertyList.stream().filter(s -> (s.getPropertyTypeRef() != null && relationSet.contains(s.getPropertyTypeRef().getTypeId()))).collect(Collectors.toMap(s -> s.getId(), s -> s, (
                value1, value2) -> {
            return value2;
        }));
        return collect;
    }


    /**
     * 获取指定模型列表显示的属性
     *
     * @return
     * @throws Exception
     */
    public List<PropertyInfo> getModelByListShowProperty(String modelId) throws Exception {
        ModelInfo modelInfo = getModelInfo(modelId);
        List<PropertyInfo> propertyInfoList = new ArrayList<>();
        if (modelInfo != null) {
            if (CollectionUtil.isNotEmpty(modelInfo.getPropertyInfoList())) {
                List<PropertyInfo> collect = modelInfo.getPropertyInfoList().stream().filter(s -> s.getFieldViewAuthTypes() != null && s.getFieldViewAuthTypes().contains(FieldViewAuthType.list)).collect(Collectors.toList());
                propertyInfoList.addAll(collect);
            }
        }
        propertyListSort(propertyInfoList, PropertyInfo.class);
        return propertyInfoList;
    }

    public void customPropertySetting(ModelPropertyParam param) throws Exception {
        ModelPropertySortInfo propertySortInfo = new ModelPropertySortInfo();
        String ownModelId = param.getOwnModelId();
        propertySortInfo.setModelId(ownModelId);
        String propertyId = param.getId();
        List<FieldViewAuthVo> fieldViewAuthList = param.getFieldViewAuthList();
        List<PropertyCategoryVo> propertyCatologList = param.getPropertyCatologList();
        ModelCustomPropertySettingInfo customInfo = new ModelCustomPropertySettingInfo();
        customInfo.setPropertyCatologList(propertyCatologList);
        customInfo.setFieldViewAuthList(fieldViewAuthList);
        Map<String, ModelCustomPropertySettingInfo> customPropertyMap = new HashMap<>();
        customPropertyMap.put(propertyId, customInfo);
        propertySortInfo.setCustomInfo(customPropertyMap);

        Query query = new Query(CriteriaWrapper.where(ModelPropertySortInfo::getModelId).is(ownModelId));
        long num = modelPropertySortMapper.count(query);
        //有数据更新
        if (num > 0) {
            Map map = genEntityMap(customInfo);
            List<MongoUpdSet> updSets = new ArrayList<>();
            genMongoUpdSetList(map, getPropertyCustomField(param.getId()), updSets);
            if (updSets.size() > 0) {
                Update update = new Update();
                int count = 0;
                for (MongoUpdSet mongoUpdSet : updSets) {
                    if (null != mongoUpdSet.getValue()) {
                        update.set(mongoUpdSet.getKey(), mongoUpdSet.getValue());
                        count++;
                    }
                }
                if (count > 0) {
                    modelPropertySortMapper.upsert(query, update);
                }
            }
        } else {
            //新增
            modelPropertySortMapper.insert(propertySortInfo);
        }
    }


    /**
     * 自定义排序
     */
    public void customPropertySort(ModelPropertySortInfo param) throws Exception {
        List<String> ids = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(param.getPropertyList())) {
            for (ModelPropertyParam property : param.getPropertyList()) {
                String id = property.getId();
                ids.add(id);
            }
            param.setPropertyIds(ids);
        }
        if (CollectionUtils.isNotEmpty(param.getPropertyIds()) && !Strings.isNullOrEmpty(param.getModelId())) {
            Query query = new Query();
            query.addCriteria(CriteriaWrapper.where(ModelPropertySortInfo::getModelId).is(param.getModelId()));
            Update update = new Update();
            update.set(CMDBTool.getFieldName(ModelPropertySortInfo::getPropertyIds), param.getPropertyIds());
            modelPropertySortMapper.upsert(query, update);
        }
    }

    /**
     * 属性id，名称校验
     *
     * @param param
     */
    private void checkPropertyData(ModelPropertyParam param, boolean isAdd) throws Exception {
        String id = param.getId();
        String name = param.getName();

        ModelInfo modelInfo = getModelInfo(param.getModelId());
        List<PropertyInfo> propertyInfoList = modelInfo.getPropertyInfoList();
        List<PropertyInfo> collect = propertyInfoList.stream().filter(s -> s.getId().equals(id) || s.getName().equals(name)).collect(Collectors.toList());
        if (isAdd) {
            //新增时，如果校验数据存在，则表示重复
            if (CollectionUtils.isNotEmpty(collect) && collect.size() > 0) {
                throw new PropertyRepeatException(id);
            }
        }
        if (!isAdd) {
            //修改时，如果校验数据大于两条(包括自己本身)，则表示重复
            if (CollectionUtils.isNotEmpty(collect) && collect.size() > 1) {
                throw new PropertyRepeatException(id);
            }
        }
    }


    /**
     * 设置权限关联字段
     *
     * @param param
     */
    private void setAuthRelatedData(ModelPropertyParam param) {
        String typeId = param.getPropertyTypeRef().getTypeId();
        String propertyId = param.getId();
        ForeignKey foreignKey = new ForeignKey();
        //权限外部关联键值设置
        if (UserKey.equals(typeId) || createrPath.equals(propertyId) || modifierPath.equals(propertyId)) {//负责人属性
            if (UserNameKey.equals(param.getId())) {//负责人名称关键键值为users
                foreignKey.setKeyName(UserKey);
            } else {
                foreignKey.setKeyName(param.getId());
            }
            foreignKey.setRelatedDataType(RelatedDataType.dataAuthUser.name());
        }
        if (OrgKey.equals(typeId)) {
            if (OrgNameKey.equals(param.getId())) {//组织名称关键键值为orgIds
                foreignKey.setKeyName(OrgIdsKey);
            } else {
                foreignKey.setKeyName(param.getId());
            }
            foreignKey.setRelatedDataType(RelatedDataType.dataAuthOrg.name());
        }
        if (GroupKey.equals(typeId)) {
            if (GroupNameKey.equals(param.getId())) {//用户组名称关键键值为groups
                foreignKey.setKeyName(GroupKey);
            } else {
                foreignKey.setKeyName(param.getId());
            }
            foreignKey.setRelatedDataType(RelatedDataType.dataAuthGroup.name());
        }
        param.setForeignKey(foreignKey);
    }


    private class ModelInfoContext {
        private ModelInfo modelInfo;

        private List<PropertyInfo> propertyList;

        public ModelInfoContext(ModelInfo modelInfo, List<PropertyInfo> propertyList) {
            this.modelInfo = modelInfo;
            this.propertyList = propertyList;
        }

        public ModelInfo getPropertyInfo() {
            return modelInfo;
        }

        public ModelInfo getModelInfo() {
            return modelInfo;
        }

        public void setModelInfo(ModelInfo modelInfo) {
            this.modelInfo = modelInfo;
        }

        public List<PropertyInfo> getPropertyList() {
            return propertyList;
        }

        public void setPropertyList(List<PropertyInfo> propertyList) {
            this.propertyList = propertyList;
        }
    }

    public <T> void getPropertyCustomInfo(List<T> modelPropertyParams, String modelId) throws Exception {
        Query query = new Query(CriteriaWrapper.where(ModelPropertySortInfo::getModelId).in(modelId));
        ModelPropertySortInfo propertySortInfo = modelPropertySortMapper.findOne(query);
        if (propertySortInfo != null) {
            Map<String, ModelCustomPropertySettingInfo> customInfo = propertySortInfo.getCustomInfo();
            if (CollectionUtils.isNotEmpty(modelPropertyParams)) {
                for (Object propertyParam : modelPropertyParams) {
                    Field idField = null;
                    try {
                        idField = propertyParam.getClass().getDeclaredField(idKey);
                        idField.setAccessible(true);
                        String id = strValueConvert(idField.get(propertyParam));
                        Field fieldViewAuthList = propertyParam.getClass().getDeclaredField(fieldViewAuthListKey);
                        fieldViewAuthList.setAccessible(true);
                        Field propertyCatologList = propertyParam.getClass().getDeclaredField(propertyCatologListKey);
                        propertyCatologList.setAccessible(true);
                        if (customInfo != null && customInfo.containsKey(id)) {
                            ModelCustomPropertySettingInfo customPropertySettingInfo = customInfo.get(id);
                            fieldViewAuthList.set(propertyParam, customPropertySettingInfo.getFieldViewAuthList());
                            propertyCatologList.set(propertyParam, customPropertySettingInfo.getPropertyCatologList());
                        }
                    } catch (NoSuchFieldException | IllegalAccessException e) {
                        log.error("Class().getDeclaredField to fail::", e);
                    }

                }
            }
        }
    }


    /**
     * 新增异常日志记录
     *
     * @param param
     */
    public void addRecordMethod(Object param) {
        String name = "";
        if (param != null && param instanceof ModelPropertyParam) {
            ModelPropertyParam info = (ModelPropertyParam) param;
            name = info.getName();
        }
        String nickName = SecurityUtils.getUser().getNickName();
        MessageSource messageSource = SpringUtil.getBean(MessageSource.class);
        logClientSimple.addBusinessLog(LogLevel.INFO.getId(), BusinessLogType.CMDB_MANAGE.getId(),
                messageSource.getMessage("mwCmdb-operation-log", new Object[]{nickName, DateUtils.now()
                        , BusinessLogType.CMDB_MANAGE.getCnName(), OperatorTypeDescEnum.add.getCname() + ModelProperty.getDesc(),
                        OperatorTypeDescEnum.add.getCname() + name, Constants.OperationStatus.FAILED}, LocaleContextHolder.getLocale()));
    }

    /**
     * 修改异常日志记录
     *
     * @param param
     */
    public void updateRecordMethod(Object param) {
        String name = "";
        if (param != null && param instanceof ModelPropertyParam) {
            ModelPropertyParam info = (ModelPropertyParam) param;
            name = info.getName();
        }
        String nickName = SecurityUtils.getUser().getNickName();
        MessageSource messageSource = SpringUtil.getBean(MessageSource.class);
        logClientSimple.addBusinessLog(LogLevel.INFO.getId(), BusinessLogType.CMDB_MANAGE.getId(),
                messageSource.getMessage("mwCmdb-operation-log", new Object[]{nickName, DateUtils.now()
                        , BusinessLogType.CMDB_MANAGE.getCnName(), OperatorTypeDescEnum.update.getCname() + ModelProperty.getDesc(),
                        OperatorTypeDescEnum.update.getCname() + name, Constants.OperationStatus.FAILED}, LocaleContextHolder.getLocale()));
    }

    /**
     * 删除异常日志记录
     *
     * @param param
     */
    private void removeRecordMethod(Object param) {
        String name = "";
        if (param != null && param instanceof ModelPropertyParam) {
            ModelPropertyParam info = (ModelPropertyParam) param;
            name = info.getName();
        }
        String nickName = SecurityUtils.getUser().getNickName();
        MessageSource messageSource = SpringUtil.getBean(MessageSource.class);
        logClientSimple.addBusinessLog(LogLevel.INFO.getId(), BusinessLogType.CMDB_MANAGE.getId(),
                messageSource.getMessage("mwCmdb-operation-log", new Object[]{nickName, DateUtils.now()
                        , BusinessLogType.CMDB_MANAGE.getCnName(), OperatorTypeDescEnum.remove.getCname() + ModelProperty.getDesc(),
                        OperatorTypeDescEnum.remove.getCname() + name, Constants.OperationStatus.FAILED}, LocaleContextHolder.getLocale()));
    }

    public List<InstanceInputFieldView> getPropertyFieldByModelId(PropertySearchParam param) throws Exception {
        ModelPropertyServiceImpl service = (ModelPropertyServiceImpl) cmdbServiceManage.getModelService(ModelPropertyServiceImpl.ID);
        List list = service.listInputProperty(param);
        ViewConvertContext context = new ViewConvertContext();
        context.put(ModelPropertyServiceImpl.ID, service);
        viewManager.getListViewObject(list, InstanceInpuFieldsView.class, null, context);
        Object ret = context.get(InstanceInpuFieldsView.Key);
        List<List<InstanceInputFieldView>> propertyList = new ArrayList();
        if (ret != null && ret instanceof List) {
            List<InstanceInpuFieldsView> retList = (List<InstanceInpuFieldsView>) ret;
            for (InstanceInpuFieldsView fieldsView : retList) {
                String type = fieldsView.getType();
                if (!propertyCatologTypeList.contains(type)) {
                    propertyList.add(fieldsView.getData());
                }
            }
        }
        List<InstanceInputFieldView> collect = propertyList.stream().flatMap(List::stream).collect(Collectors.toList());
        return collect;
    }

    /**
     * 批量新增异常日志记录
     *
     * @param param
     */
    private void batchAddRecordMethod(Object param) {

    }

    /**
     * 批量修改异常日志记录
     *
     * @param
     */
    private void batchUpdateRecordMethod(Object params) {
    }

    /**
     * 批量删除异常日志记录
     *
     * @param param
     */
    private void batchRemoveRecordMethod(Object param) {


    }


}
